package com.duyj.rule.model.datarow;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;

import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

public class DataRow {
    private final RowKey key;

    private final Map<String, Object> dataValueMap = new HashMap<>(50);

    private String tableName;

    private List<DataRow> parentList = new ArrayList<>(10);

    private Map<String, List<DataRow>> subData = new HashMap<>(16);

    private final Map<RowKey, DataRow> keyRowMap = new HashMap<>(100);

    public static DataRow instanceDataRow(String tableName, RowKey key) {
        DataRow dataRow = new DataRow(key, tableName);
        dataRow.keyRowMap.put(key, dataRow);
        return dataRow;
    }

    public static DataRow instanceDataRow(String tableName, RowKey key, Map<String, Object> map) {
        DataRow dataRow = new DataRow(key, tableName);
        dataRow.keyRowMap.put(key, dataRow);
        if (map != null) {
            dataRow.setDataValue(map);
        }
        return dataRow;
    }

    private DataRow(RowKey key, String tableName) {
        this.key = key;
        this.tableName = tableName;
    }

    /**
     * 增加一个下级
     *
     * @param subTableName 子表表名
     * @param key          key
     * @param map          map值
     * @return
     */
    public DataRow newSubData(String subTableName, RowKey key, Map<String, Object> map) {
        DataRow dataRow = this.newSubData(subTableName, key);
        dataRow.setDataValue(map);
        return dataRow;
    }

    /**
     * 增加一个下级
     *
     * @param subTableName 子表表名
     * @param key          key
     * @return
     */
    public DataRow newSubData(String subTableName, RowKey key) {
        DataRow dataRow = new DataRow(key, subTableName);
        dataRow.parentList.addAll(parentList);
        dataRow.parentList.add(this);
        for (DataRow parentRow : dataRow.parentList) {
            parentRow.collectSubData(subTableName, dataRow);
        }
        // 获取主表将key和Row做映射
        dataRow.parentList.get(0).keyRowMap.put(key, dataRow);
        return dataRow;
    }

    /**
     * 设置行列值
     *
     * @param column
     * @param value
     */
    public void setDataValue(String column, Object value) {
        dataValueMap.put(column, value);
    }

    /**
     * 批量设置行列值
     *
     * @param map
     */
    public void setDataValue(Map<String, Object> map) {
        dataValueMap.putAll(map);
    }

    /**
     * 收集当前所有后代数据,为聚合函数而用
     *
     * @param tableName
     * @param dataRow
     */

    private void collectSubData(String tableName, DataRow dataRow) {
        List<DataRow> collectDataList = subData.computeIfAbsent(tableName, s -> new ArrayList<>(10));
        collectDataList.add(dataRow);
    }

    /**
     * 获取当前行列值
     *
     * @param columnName
     * @return
     */
    public Object getColumnValue(String columnName) {
        return dataValueMap.get(columnName);
    }

    public RowKey getKey() {
        return key;
    }

    public List<DataRow> findTableList(String subTableName) {
        if (this.tableName.equals(subTableName)) {
            // return Collections.singletonList(this); 主数据需要清空所以改为其他list返回
            List<DataRow> singleList = new ArrayList<>();
            singleList.add(this);
            return singleList;
        } else {
            return subData.get(subTableName);
        }
    }

    public DataRow findDataRow(RowKey key) {
        return keyRowMap.get(key);
    }

    public DataRow findDataRow(String parentTableName) {
        if (this.tableName.equals(parentTableName)) {
            return this;
        }
        for (DataRow parent : parentList) {
            if (parent.tableName.equals(parentTableName)) {
                return parent;
            }
        }
        return null;
    }

    public DataRow findParentDataRow(String parentTableName) {
        for (DataRow parent : parentList) {
            if (parent.tableName.equals(parentTableName)) {
                return parent;
            }
        }
        return null;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    @Override
    public String toString() {
        ToStringBuilder builder = new ToStringBuilder(this);
        builder.append("key", key);
        builder.append("dataValueMap", dataValueMap);
        builder.append("tableName", tableName);
        builder.append("parentList", parentList.size());
        builder.append("subData", subData.size());
        builder.append("keyRowMap", keyRowMap.size());
        return builder.toString();
    }

    /**
     * 获取dataRow中的数据map
     *
     * @return
     */
    public Map<String, Object> getDataValueMap() {
        return dataValueMap;
    }

    /**
     * 根据RowKey，列名修改字段值
     *
     * @param key
     * @param columnName
     * @param value
     */
    public void changeOrAddValueByKeyAndColumnName(RowKey key, String columnName, Object value) {
        if (key != null && StringUtils.isNotEmpty(columnName)) {
            DataRow targetData = this.keyRowMap.get(key);
            targetData.getDataValueMap().put(columnName, value);
        }
    }


    /**
     * 根据rowKey删除行dataRow和其subData
     */
    public DataRow deleteDataRowByRowKey(RowKey key) {
        if (key == null) {
            return this;
        } else {
            if (StringUtils.isEmpty(key.getRowId())) {
                return this;
            } else if (this.key.equals(key)) {
                // 删除为根，所以整个dataRow就不存在了
                return null;
            } else {
                DataRow targetData = this.keyRowMap.get(key);
                if (targetData == null) {
                    // 删除的行未找到，直接返回
                    return this;
                }
                // 删除keyRowMap中数据
                keyRowMap.remove(targetData.getKey());
                // 收集所要删除的所有dataRow
                List<DataRow> subNeedDeleteDataRowList = targetData.subData.values().stream()
                        .flatMap(Collection::stream).collect(Collectors.toList());
                subNeedDeleteDataRowList.add(targetData);
                // 处理所有父的subData
                List<DataRow> relationParentList = targetData.parentList;
                relationParentList.forEach(relationParentDataRow -> {
                    Map<String, List<DataRow>> subDataRow = relationParentDataRow.subData;
                    subNeedDeleteDataRowList.forEach(needDeleteDataRow -> {
                        if (subDataRow.containsKey(needDeleteDataRow.getTableName())) {
                            subDataRow.get(needDeleteDataRow.getTableName()).remove(needDeleteDataRow);
                            if (CollectionUtils.isEmpty(subDataRow.get(needDeleteDataRow.getTableName()))) {
                                subDataRow.remove(needDeleteDataRow.getTableName());
                            }
                        }
                    });
                });
                // 子信息删除
                recursionDeleteSubData(targetData);
                return this;
            }
        }
    }

    /**
     * 递归删除所有子dataRow
     *
     * @param dataRow
     */
    private void recursionDeleteSubData(DataRow dataRow) {
        Map<String, List<DataRow>> subDataRow = dataRow.subData;
        subDataRow.values().forEach(subDataList -> {
            Iterator<DataRow> it = subDataList.iterator();
            while (it.hasNext()) {
                DataRow itemDataRow = it.next();
                recursionDeleteSubData(itemDataRow);
                it.remove();
                this.keyRowMap.remove(itemDataRow.getKey());
            }
        });
        Iterator<Entry<String, List<DataRow>>> it = subDataRow.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, List<DataRow>> entry = it.next();
            if (CollectionUtils.isEmpty(entry.getValue())) {
                it.remove();
            }
        }
    }

    public List<DataRow> getParentList() {
        return parentList;
    }

    public void setParentList(List<DataRow> parentList) {
        this.parentList = parentList;
    }

    public Map<String, List<DataRow>> getSubData() {
        return subData;
    }

    public void setSubData(Map<String, List<DataRow>> subData) {
        this.subData = subData;
    }

}
